package com.game.jumper.game;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import android.util.Log;

import com.game.jumper.activity.PlayLG;
import com.game.jumper.bean.Ball;
import com.game.jumper.bean.BallState;
import com.game.jumper.bean.Board;
import com.game.jumper.bean.Hand;
import com.game.jumper.bean.HandState;
import com.game.jumper.bean.Player;

/**
 * @author Administrator
 */
public class Game
{
	/**
	 * Game对象
	 */
	private static Game game = null;

	/**
	 * 当前活动的板子
	 */
	private static Board activeBoard;

	/**
	 * 当前玩家
	 */
	private static Player player = new Player();

	/**
	 * 板子ID记录
	 */
	private static Long id = 0L;

	/**
	 * 游戏结束标志 true为结束
	 */
	private boolean over;

	/**
	 * 当前游戏中板子的集合
	 */
	private static Map<Long, Board> boardMap = new TreeMap<Long, Board>();

	/**
	 * 上一次的更新时间
	 */
	private long lastUpdateTime;

	/**
	 * 最高得分
	 */
	public static int maxGoals;

	/**
	 * 触屏点击时的y坐标
	 */
	private double downHandY = -1;

	/**
	 * 触屏点击时的x坐标
	 */
	private double downHandX = -1;

	/**
	 * 触屏动作是否为移动状态，true为移动状态
	 */
	private boolean move = false;

	/**
	 * 触屏动作Y方向移动的距离
	 */
	private double deltaY;

	/**
	 * 球
	 */
	private Ball ball = new Ball();

	/**
	 * 私有构造方法
	 */
	private Game()
	{
		// 初始化第一个板子
		activeBoard = new Board(Constant.DEFAULT_BOARD_HIGHT_RATIO * Constant.Unit, Constant.DEFAULT_BOARD_WIDTH_RATIO
				* Constant.Width, Constant.DEFAULT_BOARD_THICK_RATIO * Constant.Unit);
		activeBoard.setActive(true);
		activeBoard.setBoardID(id++);
		boardMap.put(activeBoard.getBoardID(), activeBoard);
		// 初始化球
		ball.setR(Constant.R_RATIO * Constant.Unit);
		ball.setY(activeBoard.getHight() - ball.getR());
		ball.setX(activeBoard.getWidth() - ball.getR());
		lastUpdateTime = System.currentTimeMillis();


	}

	/**
	 * 开始游戏（初始化状态）
	 * 
	 * @param width 屏幕宽度
	 * @param hight 屏幕高度
	 * @return 新的一次游戏对象
	 */
	public static synchronized Game startGame(int width, int hight)
	{
		Constant.HIGHT = hight;
		Constant.Width = width;

		Constant.Unit = hight / Constant.HIGHT_UNIT;
		Constant.Vdown = Constant.Unit * Constant.V_RATIO;

		player.setGoals(0);
		id = 0L;
		boardMap.clear();

		game = new Game();
		Time.begin = System.currentTimeMillis();

		return game;
	}

	/**
	 * 获取历史最高分
	 * 
	 * @return 历史最高分
	 */
	public int getMaxGoals()
	{
		return maxGoals;
	}

	/**
	 * 获取下一周期的板子集合
	 * 
	 * @return 下一周期的板子集合
	 */
	public List<Board> getNextBoards()
	{
		return new ArrayList<Board>(boardMap.values());
	}

	/**
	 * 获取球对象
	 * 
	 * @return 球对象
	 */
	public Ball getBall()
	{
		return ball;
	}

	/**
	 * 判断游戏是否结束
	 * 
	 * @return true为结束
	 */
	public boolean isOver()
	{
		return over;
	}

	/**
	 * 更新操作
	 * 
	 * @param hand
	 */
	public void update(Hand hand)
	{
		long now = System.currentTimeMillis();
		double ticks = (now - lastUpdateTime) / 1000.0;

		if (over)
		{
			return;
		}
		if (boardMap.get(id - 1).getHight() >= Constant.DEFAULT_BOARD_HIGHT_RATIO * Constant.Unit)
		{
			Board board = Board.nextBoard();
			board.setBoardID(id++);
			boardMap.put(board.getBoardID(), board);

			Constant.Vdown = (Constant.V_RATIO + (player.getGoals() / 20 > 5 ? 5 : player.getGoals() / 20))
					* Constant.Unit;
		}

		// 存储烧掉的板子
		List<Long> deadBoardIdList = new ArrayList<Long>();
		for (Entry<Long, Board> entry : boardMap.entrySet())
		{
			Board curBoard = entry.getValue();
			curBoard.Update(ticks);
			if (curBoard.isDead())
			{
				deadBoardIdList.add(id);
			}
		}
		// 移除游戏中烧掉的板子
		for (Long deadBoardId : deadBoardIdList)
		{
			boardMap.remove(deadBoardId);
		}

		// 根据触屏动作更新
		updateByHand(hand);

		// 更新球的状态
		ball.update(ticks);
		if (ball.getY() > Constant.HIGHT)
		{
			ball.setState(BallState.Dead);
			over = true;
			PlayLG.playsound(PlayLG.sounddead);
			boardMap.clear();
			// 记录历史最高得分
			if (player.getGoals() >= maxGoals)
			{
				maxGoals = player.getGoals();
				PlayLG.thLg.writeFileData("goals.txt", String.valueOf(maxGoals));
			}
		}

		// 当球处于飞行且未死亡状态时判断球是否撞击到板子或者落到板子上
		if (ball.isFly() && !ball.isDead())
		{
			double curBallYSpeed = ball.getySpeed0();
			double curBallXSpeed = ball.getxSpeed();
			double curXofBall = ball.getX();
			double curYofBall = ball.getY();

			double predXofBall = curXofBall + ticks * curBallXSpeed;
			double predYofBall = curYofBall + ticks * Constant.Vdown - curBallYSpeed * ticks;

			// 向上飞行撞到板子上
			long hitCeilingBoardId = getHitCeilingBoardId(curXofBall, curYofBall, predXofBall, predYofBall);
			if (curBallYSpeed > 0 && hitCeilingBoardId != -1)
			{
				Board upBoard = boardMap.get(hitCeilingBoardId);
				ball.setySpeed0(0);
				ball.setY(upBoard.getHight() + ball.getR() + upBoard.getThick() * 0.5);
				// 发出撞击声音
				PlayLG.playsound(PlayLG.soundup);
			}

			// 向下掉落到板子上
			long hitFloorBoardId = getHitFloorBoardId(curXofBall, curYofBall, predXofBall, predYofBall);
			if (curBallYSpeed < 0 && hitFloorBoardId != -1)
			{
				Board downBoard = boardMap.get(hitFloorBoardId);
				downBoard.setActive(true);
				activeBoard = downBoard;
				ball.setxSpeed0(0);
				ball.setySpeed0(0);
				ball.setFly(false);
				ball.setReady(true);
				ball.setY(downBoard.getHight() - ball.getR() - downBoard.getThick() * 0.5);
				// 发出撞击声音
				PlayLG.playsound(PlayLG.sounddown);
			}
		}
		if (activeBoard != null)
			player.setGoals((int) activeBoard.getBoardID());
		lastUpdateTime = System.currentTimeMillis();
	}

	/**
	 * 获取向上撞击的板子ID
	 * 
	 * @param curXofBall
	 * @param curYofBall
	 * @param predXofBall
	 * @param predYofBall
	 * @return 向上撞击的板子ID，如果没有撞击到返回-1
	 */
	private long getHitCeilingBoardId(double curXofBall, double curYofBall, double predXofBall, double predYofBall)
	{
		for (Entry<Long, Board> entry : boardMap.entrySet())
		{
			Long tagId = entry.getKey();
			Board tagBoard = entry.getValue();
			if (tagBoard == activeBoard)
			{
				continue;
			}
			double tagHight = tagBoard.getHight();
			double tagWidth = tagBoard.getWidth();
			double halfThick = tagBoard.getThick() * 0.5;
			if (tagBoard.isLeft())
			{
				if (!(curXofBall >= tagWidth && predXofBall >= tagWidth) && curYofBall >= tagHight + halfThick
						&& predYofBall < tagHight + halfThick)
				{
					return tagId;
				}
			}
			else
			{
				if (!(curXofBall <= Constant.Width - tagWidth && predXofBall <= Constant.Width - tagWidth)
						&& curYofBall >= tagHight + halfThick && predYofBall < tagHight + halfThick)
				{
					return tagId;
				}
			}
		}
		return -1;
	}

	/**
	 * 获取掉落到的板子ID
	 * 
	 * @param curXofBall
	 * @param curYofBall
	 * @param predXofBall
	 * @param predYofBall
	 * @return 掉落到的板子ID,如果没有则返回-1
	 */
	private long getHitFloorBoardId(double curXofBall, double curYofBall, double predXofBall, double predYofBall)
	{
		for (Entry<Long, Board> entry : boardMap.entrySet())
		{
			Long tagId = entry.getKey();
			Board tagBoard = entry.getValue();
			double tagHight = tagBoard.getHight();
			double tagWidth = tagBoard.getWidth();
			double halfThick = tagBoard.getThick() * 0.5;
			if (tagBoard.isLeft())
			{
				if (!(curXofBall >= tagWidth && predXofBall >= tagWidth) && curYofBall <= tagHight - halfThick
						&& predYofBall > tagHight - halfThick)
				{
					return tagId;
				}
			}
			else
			{
				if (!(curXofBall <= Constant.Width - tagWidth && predXofBall <= Constant.Width - tagWidth)
						&& curYofBall <= tagHight - halfThick && predYofBall > tagHight - halfThick)
				{
					return tagId;
				}
			}
		}
		return -1;
	}

	/**
	 * 根据触屏动作更新状态
	 * 
	 * @param hand
	 */
	private void updateByHand(Hand hand)
	{
		try
		{
			// 板子Y方向最大的形变
			double maxY = Constant.MAX_DELTA_Y_RATIO * Constant.Unit;
			// 板子未激活时不触发动作
			if (!activeBoard.isActive())
			{
				return;
			}
			// 当滑动屏幕时
			if (hand.getHandState() == HandState.MOVE)
			{
				// 首次触发Move状态时更新
				if (!move)
				{
					downHandY = hand.getY();
					move = true;
					downHandX = hand.getX();
					activeBoard.setRecover(true);
					ball.setReady(true);
				}

				deltaY = hand.getY() - downHandY;

				// �����ƶ��ķ�Χ
				if (deltaY < 0)
				{
					deltaY = 0;
				}
				if (deltaY > maxY)
				{
					deltaY = maxY;
				}
				if (deltaY > 0 && deltaY < maxY)
				{
					// 弯曲板子的声音
					PlayLG.playsound(PlayLG.soundboard);
				}

				activeBoard.getLocations().clear();
				// 依据板子所处位置绘制弯曲的点集合
				if (activeBoard.isLeft())
				{
					for (int i = 0; i <= activeBoard.getWidth(); i += 10)
					{
						activeBoard.addLocation(i,
								deltaY * Math.pow(i * 1.0 / activeBoard.getWidth(), 2) + activeBoard.getHight());
					}
					ball.setY(deltaY * Math.pow(ball.getX() / activeBoard.getWidth(), 2) + activeBoard.getHight()
							- ball.getR());
				}
				else
				{
					for (int i = 0; i <= activeBoard.getWidth(); i += 10)
					{
						activeBoard.addLocation(Constant.Width - i,
								deltaY * Math.pow(i * 1.0 / activeBoard.getWidth(), 2) + activeBoard.getHight());
					}
					ball.setY(deltaY * Math.pow((Constant.Width - ball.getX()) / activeBoard.getWidth(), 2)
							+ activeBoard.getHight() - ball.getR());
				}

			}
			else if (hand.getHandState() == HandState.UP)
			{
				if (move)
				{
					activeBoard.SetD(deltaY);
					double dy = hand.getY() - downHandY;
					double dx = hand.getX() - downHandX;
					dx = -dx;
					// 初始化速度
					double maxV = Math.sqrt(Constant.G_RATIO * Constant.Unit * Constant.HIGHT * Constant.BALL_V_RATIO);
					double v = (deltaY * deltaY) / (maxY * maxY) * maxV;

					double hypotxy = Math.hypot(dx, dy);
					if (hypotxy == 0)
					{
						hypotxy = Constant.Unit;
					}
					double vx = dx * v / hypotxy;
					double vy = dy * v / hypotxy;
					if (vy <= 0)
					{
						if (dx > 0)
						{
							double expX = ball.getX() + Constant.BALL_VX_RATIO * Constant.Unit;
							if (activeBoard.isLeft() && expX > activeBoard.getWidth())
							{
								ball.setX(activeBoard.getWidth() - ball.getR());
							}
							else if (!activeBoard.isLeft() && expX > Constant.Width - ball.getR())
							{
								ball.setX(Constant.Width - ball.getR());
							}
							else
							{
								ball.setX(expX);
							}
						}
						if (dx < 0)
						{
							double expX = ball.getX() - Constant.BALL_VX_RATIO * Constant.Unit;
							if (activeBoard.isLeft() && expX < ball.getR())
							{
								ball.setX(ball.getR());
							}
							else if (!activeBoard.isLeft() && expX < Constant.Width - activeBoard.getWidth())
							{
								ball.setX(Constant.Width - activeBoard.getWidth() + ball.getR());
							}
							else
							{
								ball.setX(expX);
							}
						}
					}
					else
					{
						if (vx > Constant.MAX_VX_RATIO * Constant.Unit)
						{
							vx = Constant.MAX_VX_RATIO * Constant.Unit;
						}
						if (vx < -1 * Constant.MAX_VX_RATIO * Constant.Unit)
						{
							vx = -1 * Constant.MAX_VX_RATIO * Constant.Unit;
						}
						ball.doFly(vx, vy + Constant.MIN_VY_RATIO * Constant.Unit);
						activeBoard.setActive(false);

						// ��������
						PlayLG.playsound(PlayLG.soundfly);
					}
				}
				ball.setReady(false);
				// activeBoard.setRecover(false);

				downHandY = -1;
				move = false;
			}
		}
		catch (Exception ex)
		{
			Log.i(ex.toString(), "");
		}
	}

	/**
	 * 获取当前玩家
	 * 
	 * @return 当前玩家
	 */
	public static Player getPlayer()
	{
		return player;
	}

}
